package ar.edu.uba.fi.jmit.aspecter.monitor.invocationCounter;

import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.LinkedList;
import java.util.List;

import javassist.ClassPool;
import javassist.CtClass;
import ar.edu.uba.fi.jmit.aspecter.AspecterTestCase;
import ar.edu.uba.fi.jmit.aspecter.core.Constants;
import ar.edu.uba.fi.jmit.aspecter.core.MethodDefinition;
import ar.edu.uba.fi.jmit.aspecter.core.ResourceProperties;
import ar.edu.uba.fi.jmit.aspecter.core.injector.Injector;
import ar.edu.uba.fi.jmit.aspecter.monitor.testUtils.EventPriorityMock;
import ar.edu.uba.fi.jmit.aspecter.monitor.testUtils.MockEvent;
import ar.edu.uba.fi.jmit.aspecter.monitor.testUtils.SenderFactoryMock;

public class InvocationCounterMethodInjectorTestCase extends AspecterTestCase {
	
	MethodDefinition theMethodDefinition;
	
	@Override
	protected void setUp() throws Exception {
		super.setUp();
		SenderFactoryMock.clean();
		theMethodDefinition = new MethodDefinition(
				ar.edu.uba.fi.jmit.aspecter.monitor.testUtils.MonitorTarget.class,
				"theMethod", 
				new LinkedList<Class<?>>(), 
				void.class);
	}

	public void testInjectOnGetXMethod() {
		try {
			Injector injector = new InvocationCounterMethodInjector(theMethodDefinition, "monitoreo_testInjectOnGetXMethod", "id");
			CtClass ctClazz = ClassPool.getDefault().getAndRename("ar.edu.uba.fi.jmit.aspecter.monitor.testUtils.MonitorTarget", getNextClassName());
			injector.inject(ctClazz);
			Class<?> clazz = ctClazz.toClass();
			Object object = clazz.newInstance();
			for(int i = 0; i< 15; i++) {
				assertEquals(clazz.getMethod("getMyInvocationCounter").invoke(object), SenderFactoryMock.getSenderInstance().getSendedEvents().size());
				assertEquals(i, SenderFactoryMock.getSenderInstance().getSendedEvents().size());
				clazz.getMethod("theMethod").invoke(object);
			}
			
			for(int i = 0; i< 15; i++) {
				assertEquals(clazz.getMethod("getMyInvocationCounter").invoke(object), SenderFactoryMock.getSenderInstance().getSendedEvents().size());
				assertEquals(15, SenderFactoryMock.getSenderInstance().getSendedEvents().size());
				clazz.getMethod("theMethod", int.class).invoke(object, 1);
			}
		} catch (Exception e) {
			fail(e);
		}
	}
	
	public void testObjectId() {
		try {
			Injector injector = new InvocationCounterMethodInjector(theMethodDefinition, "monitoreo_testInjectOnGetXMethod", "id");
			CtClass ctClazz = ClassPool.getDefault().getAndRename("ar.edu.uba.fi.jmit.aspecter.monitor.testUtils.MonitorTarget", getNextClassName());
			injector.inject(ctClazz);
			Class<?> clazz = ctClazz.toClass();
			Object object = clazz.newInstance();
			clazz.getMethod("setId", int.class).invoke(object, 10);
			clazz.getMethod("theMethod").invoke(object);
			List<MockEvent> list = SenderFactoryMock.getSenderInstance().getSendedEvents();
			assertEquals(10, list.get(0).getData().get(ResourceProperties.getProperty(Constants.EVENT_ID_OBJECT_KEY)));
			
		} catch (Exception e) {
			fail(e);
		} 
	}
	
	public void testObjectIdAsMethod() {
		try {
			Injector injector = new InvocationCounterMethodInjector(theMethodDefinition, "monitoreo_testInjectOnGetXMethod", "getId()");
			CtClass ctClazz = ClassPool.getDefault().getAndRename("ar.edu.uba.fi.jmit.aspecter.monitor.testUtils.MonitorTarget", getNextClassName());
			injector.inject(ctClazz);
			Class<?> clazz = ctClazz.toClass();
			Object object = clazz.newInstance();
			clazz.getMethod("setId", int.class).invoke(object, 10);
			clazz.getMethod("theMethod").invoke(object);
			List<MockEvent> list = SenderFactoryMock.getSenderInstance().getSendedEvents();
			assertEquals(10, list.get(0).getData().get(ResourceProperties.getProperty(Constants.EVENT_ID_OBJECT_KEY)));
			
		} catch (Exception e) {
			fail(e);
		} 
	}
	
	public void testSendedData() {
		try {
			String className = getNextClassName();
			Injector injector = new InvocationCounterMethodInjector(theMethodDefinition, "monitoreo_testInjectOnGetXMethod", "id");
			CtClass ctClazz = ClassPool.getDefault().getAndRename("ar.edu.uba.fi.jmit.aspecter.monitor.testUtils.MonitorTarget", className);
			injector.inject(ctClazz);
			Class<?> clazz = ctClazz.toClass();
			Object object = clazz.newInstance();
			clazz.getMethod("setId", int.class).invoke(object, 10);
			clazz.getMethod("theMethod").invoke(object);
			List<MockEvent> list = SenderFactoryMock.getSenderInstance().getSendedEvents();
			assertEquals(10, list.get(0).getData().get(ResourceProperties.getProperty(Constants.EVENT_ID_OBJECT_KEY)));
			assertEquals("monitoreo_testInjectOnGetXMethod", list.get(0).getData().get(ResourceProperties.getProperty(Constants.EVENT_MONITOR_NAME_KEY)));
			Date eventDate = (Date) list.get(0).getData().get(ResourceProperties.getProperty(Constants.EVENT_MONITOR_DATE));
			Calendar eventCalendar = new GregorianCalendar();
			eventCalendar.setTime(eventDate);
			Calendar today = new GregorianCalendar();
			assertEquals(eventCalendar.get(Calendar.YEAR), today.get(Calendar.YEAR));
			assertEquals(eventCalendar.get(Calendar.MONTH), today.get(Calendar.MONTH));
			assertEquals(eventCalendar.get(Calendar.DAY_OF_YEAR), today.get(Calendar.DAY_OF_YEAR));
			assertEquals(eventCalendar.get(Calendar.HOUR), today.get(Calendar.HOUR));
			assertEquals(eventCalendar.get(Calendar.MINUTE), today.get(Calendar.MINUTE));
			assertEquals("void_ar.edu.uba.fi.jmit.aspecter.monitor.testUtils.MonitorTarget.theMethod()", list.get(0).getSource());
			assertEquals(EventPriorityMock.NORMAL, list.get(0).getPriority());
		} catch (Exception e) {
			fail(e);
		} 
	}

}
